package ai.people.netmon.warning.service.impl;

import ai.people.netmon.framework.domain.warning.dto.AnalysisRequestContext;
import ai.people.netmon.framework.domain.warning.request.account.AccountWarningInfoRequest;
import ai.people.netmon.framework.domain.warning.request.subject.SubjectWarningRequest;
import ai.people.netmon.framework.domain.warning.vo.MessageContentVO;
import ai.people.netmon.framework.exception.enums.CommonEnum;
import ai.people.netmon.framework.model.response.PageResponse;
import ai.people.netmon.framework.model.response.Result;
import ai.people.netmon.framework.utils.AssertUtils;
import ai.people.netmon.framework.utils.ResultUtil;
import ai.people.netmon.warning.assist.LockAction;
import ai.people.netmon.warning.service.WarningAnalysisTaskLink;
import ai.people.netmon.warning.service.WarningAnalysisTaskOrder;
import ai.people.netmon.warning.service.WarningSpeechTemplateService;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * impl预警分析消息搜索任务
 *
 * @author LiGuanNan
 * @date 2022/8/15 10:50
 */
@Slf4j
@Service
public class WarningAnalysisMessageSearchTaskImpl extends WarningAnalysisTaskLink implements WarningAnalysisTaskOrder {

    @Autowired
    private DoMessageSearchTaskFactory doMessageSearchTaskFactory;

    /**
     * 本地缓存（由于消息数据量较大，使用redis缓存有大key问题，所以使用给本地缓存）
     */
    static Cache<String, List<MessageContentVO>> caffeineCache = null;

    @PostConstruct
    public void init(){
        caffeineCache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.HOURS)
                .maximumSize(1024 * 1024 * 100)
                .build();
    }

    /**
     * 得到顺序
     *
     * @return int
     */
    @Override
    public int getOrder() {
        return 20;
    }

    /**
     * 做任务
     *
     * @param paramContext 参数上下文
     * @return {@link T}
     */
    @Override
    public <T> Result<List<T>> doTask(AnalysisRequestContext<T> paramContext) {
        List<MessageContentVO> vos = doMessageSearchTaskFactory.findTask(paramContext.getAnalysisDimension()).searchMessageContent(paramContext);
        paramContext.setMessageContentList(vos);
        return ResultUtil.success(vos);
    }

    /**
     * 执行消息搜索任务
     *
     * @author ligua
     * @date 2022/08/15
     */
    interface DoMessageSearchTask {

        /**
         * 得到消息内容
         *
         * @param paramContext 参数上下文
         * @return {@link List}<{@link MessageContentVO}>
         */
        <T> List<MessageContentVO> searchMessageContent(AnalysisRequestContext<T> paramContext);
    }


    /**
     * 账户信息搜索任务
     *
     * @author ligua
     * @date 2022/08/15
     */
    @Component("warningAnalysis_messageSearchTask_1")
    static class AccountMessageSearchTask implements DoMessageSearchTask{

        @Value("${warning.analysis.cache.switch}")
        private Boolean analysisCacheSwitch;

        @Autowired
        private LockAction lockAction;

        @Autowired
        private WarningSpeechTemplateService<AccountWarningInfoRequest, MessageContentVO> accountWarningServiceImpl;

        /**
         * 得到消息内容
         *
         * @param paramContext 参数上下文
         * @return {@link List}<{@link MessageContentVO}>
         */
        @Override
        public <T>  List<MessageContentVO> searchMessageContent(AnalysisRequestContext<T> paramContext) {
            return lockAction.doLockTask(String.format("warning:analysis:account:lock:%s",paramContext.getBusinessId()), 6, ()-> getMessageContentVos(paramContext));
        }

        /**
         * 得到消息内容vos
         *
         * @param paramContext 参数上下文
         * @return {@link List}<{@link MessageContentVO}>
         */
        private <T> List<MessageContentVO> getMessageContentVos(AnalysisRequestContext<T> paramContext) {
            String cacheKey = String.format("warning:analysis:account:%s:%s-%s", paramContext.getBusinessId(),
                    paramContext.getStartDate() != null ? paramContext.getStartDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(): 0,
                    paramContext.getEndDate() != null ? paramContext.getEndDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(): 0);
            List<MessageContentVO> voList = caffeineCache.getIfPresent(cacheKey);
            if(voList != null && analysisCacheSwitch){
                return voList;
            }
            List<MessageContentVO> vos = Lists.newArrayList();
            AccountWarningInfoRequest accountWarningRequest = new AccountWarningInfoRequest();
            accountWarningRequest.setAccountId(paramContext.getBusinessId());
            if(paramContext.getStartDate() != null){
                accountWarningRequest.setStartTime(paramContext.getStartDate());
            }
            if(paramContext.getEndDate() != null){
                accountWarningRequest.setEndTime(paramContext.getEndDate());
            }
            accountWarningRequest.setPageNo(0);
            accountWarningRequest.setPageSize(10000);
            PageResponse<MessageContentVO> listPageResponse = accountWarningServiceImpl.searchQuery(accountWarningRequest);
            if(listPageResponse != null && !CollectionUtils.isEmpty(listPageResponse.getList())){
                vos = (List<MessageContentVO>) listPageResponse.getList();
            }
            caffeineCache.put(cacheKey, vos);
            return vos;
        }
    }

    /**
     * 主题信息搜索任务
     *
     * @author ligua
     * @date 2022/08/15
     */
    @Component("warningAnalysis_messageSearchTask_0")
    static class SubjectMessageSearchTask implements DoMessageSearchTask{

        @Value("${warning.analysis.cache.switch}")
        private Boolean analysisCacheSwitch;

        @Autowired
        private LockAction lockAction;

        @Autowired
        private WarningSpeechTemplateService<SubjectWarningRequest, MessageContentVO> warningSubjectServiceImpl;

        /**
         * 得到消息内容
         *
         * @param paramContext 参数上下文
         * @return {@link List}<{@link MessageContentVO}>
         */
        @Override
        public <T>  List<MessageContentVO> searchMessageContent(AnalysisRequestContext<T> paramContext) {
            return lockAction.doLockTask(String.format("warning:analysis:subject:lock:%s",paramContext.getBusinessId()), 6, ()-> getMessageContentVos(paramContext));
        }

        /**
         * 得到消息内容vos
         *
         * @param paramContext 参数上下文
         * @return {@link List}<{@link MessageContentVO}>
         */
        private <T> List<MessageContentVO> getMessageContentVos(AnalysisRequestContext<T> paramContext) {
            String cacheKey = String.format("warning:analysis:subject:%s:%s-%s", paramContext.getBusinessId(),
                    paramContext.getStartDate() != null ? paramContext.getStartDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(): 0,
                    paramContext.getEndDate() != null ? paramContext.getEndDate().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(): 0);
            List<MessageContentVO> voList = caffeineCache.getIfPresent(cacheKey);
            if(voList != null && analysisCacheSwitch){
                return voList;
            }
            List<MessageContentVO> vos = Lists.newArrayList();
            SubjectWarningRequest subjectWarningRequest = new SubjectWarningRequest();
            subjectWarningRequest.setSubjectId(paramContext.getBusinessId());
            if(paramContext.getStartDate() != null){
                subjectWarningRequest.setStartTime(paramContext.getStartDate());
            }
            if(paramContext.getEndDate() != null){
                subjectWarningRequest.setEndTime(paramContext.getEndDate());
            }
            subjectWarningRequest.setPageNo(0);
            subjectWarningRequest.setPageSize(10000);
            PageResponse<MessageContentVO> listPageResponse = warningSubjectServiceImpl.searchQuery(subjectWarningRequest);
            if(listPageResponse != null && !CollectionUtils.isEmpty(listPageResponse.getList())){
                vos = (List<MessageContentVO>) listPageResponse.getList();
            }
            caffeineCache.put(cacheKey, vos);
            return vos;
        }
    }


    /**
     * 查找真正执行的任务
     */
    @Component("doMessageSearchTaskFactory")
    static class DoMessageSearchTaskFactory {

        @Autowired
        private Map<String, DoMessageSearchTask> doMessageSearchTaskMap;

        /**
         * 找到任务
         *
         * @param analysisDimension 分析维度
         * @return {@link DoMessageSearchTask}
         */
        public DoMessageSearchTask findTask(Integer analysisDimension) {
            DoMessageSearchTask doMessageSearchTask = doMessageSearchTaskMap.get(String.format("warningAnalysis_messageSearchTask_%d", analysisDimension));
            AssertUtils.isNotNull(doMessageSearchTask, CommonEnum.OPT_NOT_SUPPORT);
            return doMessageSearchTask;
        }
    }
}
